#include <iostream>
#include <mutex>

// 单例模式 一个类只能得到一个实例
// 1. 构造函数私有化, 去掉拷贝构造和拷贝赋值,移动构造，移动赋值
// 2. 定义一个唯一实例
// 3. 定义获取实例的静态成员方法
//
// 饿汉式 还没有用到 就已经创建好了实例对象
// 懒汉式 需要时才创建

#if 0
// 饿汉式  一定是线程安全的
// 构造函数中可能需要依赖其它耗时操作，会增加软件的启动时间
// 可能软件后期并不需要用到等
class Singleton {
public:
    static Singleton* getInstance() {
        return &instance;
    }

private:
    static Singleton instance;
    Singleton() {
    }
    Singleton(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton& operator=(Singleton&&) = delete;
};

Singleton Singleton::instance;  // 类外定义 类的静态成员变量
int main() {
    Singleton* p1 = Singleton::getInstance();
    Singleton* p2 = Singleton::getInstance();
    Singleton* p3 = Singleton::getInstance();

    std::cout << (p1 == p2) << " " << (p2 == p3) << std::endl;
    return 0;
}
#endif

#if 0
std::mutex mtx;
// 懒汉式 将对象实例化推迟到第一次使用的时候
class Singleton {
public:
    // 线程不安全 会发生竞态条件（竞态条件（Race
    // Condition）是指在多线程或多进程环境中，由于不恰当的执行顺序而导致结果依赖于线程或进程执行的相对速度和时序的现象。）
    // 不可重入 （重入会导致线程安全问题或逻辑不正确）
    static Singleton* getInstance() {
        if (!instance) {
#if 0
            instance = new Singleton;
            // 考虑两种不可重入的情况：
            // 1. #1 开辟内存 #2 给instance赋值 #3 构造对象
            // 2. #1 开辟内存 #2 构造对象 #3 给instance赋值
            //
            // 汇编指令上 上述两种执行顺序都有可能（底层乱序是出于优化考虑）
            // 不管是哪种情况 都是线程不安全的 都会发生竞态条件 都是属于不可重入
            // 所以必须要互斥执行
#endif
            // 线程安全的情况 锁+双重判断
            std::lock_guard<std::mutex> lock(mtx);
            if (!instance) {  // 双重判断 保证之后的等待锁的线程能够正确执行
                instance = new Singleton();
            }
        }
        return instance;
    }

private:
    static Singleton* volatile instance;
    Singleton() {
    }
    Singleton(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton& operator=(Singleton&&) = delete;
};
Singleton* volatile Singleton::instance = nullptr;

int main() {
    Singleton* p1 = Singleton::getInstance();
    Singleton* p2 = Singleton::getInstance();
    Singleton* p3 = Singleton::getInstance();
}
#endif

// 懒汉式 将对象实例化推迟到第一次使用的时候
class Singleton {
public:
    static Singleton* getInstance() {
        // 线程安全的
        // 函数的静态局部变量的初始化，在汇编指令上已经自动添加线程互斥指令了
        static Singleton instance;  // 第一次运行时创建
        return &instance;
    }

private:
    Singleton() {
    }
    Singleton(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton& operator=(Singleton&&) = delete;
};

int main() {
    Singleton* p1 = Singleton::getInstance();
    Singleton* p2 = Singleton::getInstance();
    Singleton* p3 = Singleton::getInstance();
    std::cout << (p1 == p2) << " " << (p2 == p3) << std::endl;
}
